package controller

import (
	"common/zapx"
	"context"
	"errors"
	"github.com/minio/minio-go/v7"
	"go.uber.org/zap"
	"google.golang.org/genproto/googleapis/rpc/errdetails"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"io"
	"minio/internal/logic"
	"minio/internal/pb"
)

type UploadService struct {
	pb.UnimplementedMinioServiceServer
}

// Upload 文件上传
func (us *UploadService) Upload(req pb.MinioService_UploadServer) error {
	//文件数据
	var fileFullData []byte
	var l int
	//文件的md5值,文件名称
	var fileMd5, fileName string
	opt := minio.PutObjectOptions{}
	for {
		r, err := req.Recv()
		if err != nil {
			if errors.Is(err, io.EOF) {
				//传输结束了
				ret, err := logic.CompleteUpload(fileName, fileMd5, fileFullData, opt)
				if err != nil {
					return err
				}
				return req.SendAndClose(ret)
			} else {
				zapx.Logger.Error("接收客户端消息失败", zap.Error(err))
				return status.New(codes.Internal, "内部错误").Err()
			}
		}
		fileMd5 = r.File.FileMd5
		fileName = r.File.FileName
		l += len(r.File.Data)
		fileFullData = append(fileFullData, r.File.Data...)
		if r.File.Metadata != nil {
			opt.UserMetadata = r.File.Metadata
		}
		if r.File.Tag != nil {
			opt.UserTags = r.File.Tag
		}
		if r.File.ContentType != nil {
			opt.ContentType = *r.File.ContentType
		}
		if r.File.Expires != nil {
			opt.Expires = r.File.Expires.AsTime()
		}
	}
}

// GetUrl 获取链接
func (us *UploadService) GetUrl(ctx context.Context, req *pb.UrlRequest) (*pb.UrlResponse, error) {
	uri, err := logic.GetUriByKey(req.Key)
	if err != nil {
		zapx.Logger.Error("请求 minio 获取链接失败", zap.Error(err))
		st, ste := status.New(codes.Internal, "获取链接失败").WithDetails(
			&errdetails.BadRequest{
				FieldViolations: []*errdetails.BadRequest_FieldViolation{
					{
						Field:       "MINIO_OBJECT_OPERATE",
						Description: err.Error(),
					},
				},
			},
		)
		if ste != nil {
			return nil, errors.New("内部错误")
		}
		return nil, st.Err()
	}
	return &pb.UrlResponse{
		Uri: uri,
		Key: req.Key,
	}, nil
}

func (us *UploadService) Exists(ctx context.Context, req *pb.ExistsRequest) (*pb.ExistsResponse, error) {
	if err := logic.ObjectExists(req.Key); err != nil {
		return nil, err
	}
	return &pb.ExistsResponse{}, nil
}
